#include "serial_drive.h"

Status InitQueue(SqQueue &Q)
{
      //构造一个空队列Q
      Q.base=(QElemType*)malloc( MAXQSIZE*sizeof(QElemType));
      if(!Q.base) 
        {
            return false;
            printf("***************Queue fail");//存储分配失败
        }
      Q.front=Q.rear=0;
      return true;
}

int QueueLength(SqQueue &Q)
{
      //返回Q的长度
      return ((Q.rear-Q.front+MAXQSIZE)%MAXQSIZE);
}

Status EnQueue(SqQueue &Q,QElemType *e,int num)
{
      //插入元素e为Q的新的队尾元素
      if((Q.rear+num)%MAXQSIZE==Q.front) return ERROR;//队列满
      if(Q.rear+num>MAXQSIZE)//到数据末尾需要注意内存拷贝的问题
	{
            memcpy(&Q.base[Q.rear],&e[0],MAXQSIZE-Q.rear);
            memcpy(&Q.base[0],&e[MAXQSIZE-Q.rear],num+Q.rear-MAXQSIZE);
	}
      else
            memcpy(&Q.base[Q.rear],&e[0],num);
      Q.rear=(Q.rear+num)%MAXQSIZE;
      return OK;
}
//出栈一个
Status DeQueue(SqQueue &Q,QElemType &e)
{
      //若队列不为空，则删除Q的对头文件，用e返回其值，并返回ok
      //否则返回ERROR
      if(Q.front==Q.rear) return ERROR;
      e=Q.base[Q.front];
      Q.front=(Q.front+1)%MAXQSIZE;
      return OK;
}
//出栈多个
int DeQueue(SqQueue &Q,QElemType *e,int num)
{
      //若队列不为空，则删除Q的对头文件，用e返回其值，并返回ok
      //否则返回ERROR
    int length=(Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
    if(length==0) return 0;
    if(num>0)
    { 
        if(length>num-1)
        {
            if(Q.front+num<MAXQSIZE)
                { 
                  memcpy(&e[0],&Q.base[Q.front],num);
                }
            else
                {
                    memcpy(&e[0],&Q.base[Q.front],MAXQSIZE-Q.front);
                    memcpy(&e[MAXQSIZE-Q.front],&Q.base[0],Q.front+num-MAXQSIZE);
                }
            Q.front=(Q.front+num)%MAXQSIZE;                       
            return num;
        }
        else
        {
            if(Q.front+length<MAXQSIZE)
            {
                memcpy(&e[0],&Q.base[Q.front],length);
            }
            else
            {
                memcpy(&e[0],&Q.base[Q.front],MAXQSIZE-Q.front);
                memcpy(&e[MAXQSIZE-Q.front],&Q.base[0],Q.front+length-MAXQSIZE);
            }
            Q.front=(Q.front+length)%MAXQSIZE; 
            return length;
        }   
    }
    else
        return 0;   
}

int open_serial_port(const char * device, uint32_t baud_rate)
{
  int fd = open(device, O_RDWR | O_NOCTTY);
  //printf("**********************%d\n",fd);
  if (fd == -1)
  {
    perror(device);
    return -1;
  }
 
  // Flush away any bytes previously read or written.
  int result = tcflush(fd, TCIOFLUSH);
  if (result)
  {
    perror("tcflush failed");  // just a warning, not a fatal error
  }
 
  // Get the current configuration of the serial port.
  struct termios options;
  result = tcgetattr(fd, &options);
  if (result)
  {
    perror("tcgetattr failed");
    close(fd);
    return -1;
  }
 
  // Turn off any options that might interfere with our ability to send and
  // receive raw binary bytes.
  options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF);
  options.c_oflag &= ~(ONLCR | OCRNL);
  options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);

  // Set up timeouts: Calls to read() will return as soon as there is
  // at least one byte available or when 100 ms has passed.
  options.c_cc[VTIME] = 0;  //VTIME与VMIN配合使用，是指限定的传输或等待的最长时间 单位：0.1S
  options.c_cc[VMIN] = 1;//设置非规范模式下的超时时长和最小字符数：阻塞模式起作用

  // This code only supports certain standard baud rates. Supporting
  // non-standard baud rates should be possible but takes more work.
  switch (baud_rate)
  {
  case 4800:   cfsetospeed(&options, B4800);   break;
  case 9600:   cfsetospeed(&options, B9600);   break;
  case 19200:  cfsetospeed(&options, B19200);  break;
  case 38400:  cfsetospeed(&options, B38400);  break;
  case 115200: cfsetospeed(&options, B115200); break;
  case 230400: cfsetospeed(&options, B230400); break;
  default:
    fprintf(stderr, "warning: baud rate %u is not supported, using 9600.\n", baud_rate);
    cfsetospeed(&options, B9600);
    break;
  }
  cfsetispeed(&options, cfgetospeed(&options));
 
  result = tcsetattr(fd, TCSANOW, &options);
  if (result)
  {
    perror("tcsetattr failed");
    close(fd);
    return -1;
  }
 
  return fd;
}
 
// Writes bytes to the serial port, returning 0 on success and -1 on failure.
int write_port(int fd, uint8_t * buffer, size_t size)
{
  ssize_t result = write(fd, buffer, size);
  if (result != (ssize_t)size)
  {
    perror("failed to write to port");
    return -1;
  }
  return 0;
}
 
// Reads bytes from the serial port.
// Returns after all the desired bytes have been read, or if there is a
// timeout or other error.
// Returns the number of bytes successfully read into the buffer, or -1 if
// there was an error reading.
ssize_t read_port(int fd, uint8_t * buffer, size_t size)
{
  size_t received = 0;
  while (received < size)
  {
    ssize_t r = read(fd, buffer + received, size - received);
    if (r < 0)
    {
      perror("failed to read from port");
      return -1;
    }
    if (r == 0)
    {
      printf("\rRCV timeout");
    }
    received += r;
  }
  return received;
}